package src;
import java.io.*;

/**
 * Clase Mapa
 * @author Alonso, Reissing, Veroni
 *
 */
public class Mapa {
	
	protected Piso [][] casillas;
	protected Posicion inicial, terminal;
	
	/**
	 * Crea un objeto Mapa a partir de un archivo
	 * @param archivo Nombre del archivo
	 * @throws ErrorEnCargarArchivo
	 */
	public Mapa(String archivo) throws ErrorEnCargarArchivo {
		
		try{
            // Abrimos el archivo
			InputStream fstream = this.getClass().getResourceAsStream("/src/"+archivo); 
			//FileInputStream fstream = new FileInputStream(getClass().getResource(archivo).getPath());
            // Creamos el objeto de entrada
            DataInputStream entrada = new DataInputStream(fstream);
            // Creamos el Buffer de Lectura
            BufferedReader buffer = new BufferedReader(new InputStreamReader(entrada));
            String strLinea;
            // Leer la primera linea para obtener parametros del nivel
            if ((strLinea = buffer.readLine()) != null)   {
            	
            	int i=Integer.parseInt(strLinea);
                if ((strLinea = buffer.readLine()) != null){
                	int j=Integer.parseInt(strLinea);
                	casillas= new Piso[i][j];
                }
                else{
                	buffer.close();
                	entrada.close();
                	throw new ErrorEnCargarArchivo("Error en la carga de mapa. Intentelo de nuevo");
                	
                }
                //leemos cada uno de las casillas
                for (int j=0; j<casillas.length; j++){
                	if ((strLinea = buffer.readLine()) != null) 
                		for (i=0; i<casillas[0].length; i++){
                			            			
                			Piso piso;
                			
                			char terreno=strLinea.charAt(1+i*7);
                			piso=crearPiso(terreno);
                			casillas[i][j]=piso;
                			Posicion posp=new Posicion(i,j);
                			piso.setPosicion(posp);
                			
                			char obs=strLinea.charAt(3+i*7);
                			Obstaculo o=crearObstaculo(obs);
                			boolean hayObstaculo=o!=null;
                			if (hayObstaculo)
                				piso.agregarObstaculo(o);
                				
                			
                			char pr=strLinea.charAt(5+i*7);
                			
                			switch (pr){
                			case 'N':
                			case 'D':
                			case 'U':
                			case 'E': 	{ Premio p=crearPremio(pr);
                						  if (p!=null)
                								piso.agregarPremio(p);
                						  break;
                						}
                			case 'X': 
                			case 'Y':   { Coleccionable c=crearColeccionable(pr);
                						  if (!hayObstaculo&&c!=null)
                									piso.agregarColeccionable(c);
                						  break;
                						}  
                			case '@':   {inicial= new Posicion(i,j);
                						 break;
                						}
                			case '#': 	{terminal=new Posicion(i,j);
                						 break;
                						}
                			default: throw new ErrorEnCargarArchivo("Error en el nivel");
                			}
                			
                	}
                }
                	
            }
            // Cerramos el archivo
            entrada.close();
            buffer.close();
        }catch (Exception e){ //Catch de excepciones
            throw new ErrorEnCargarArchivo("Ocurrio un error en cargar el nivel. Intentelo de nuevo ");
        }
}
		
	
	private Coleccionable crearColeccionable(char c) throws ErrorEnCargarArchivo {
		Coleccionable col=null;
		switch (c){
		case 'X': {col=new Cono();
					break;
					}
		case 'Y': {col=new Baliza();
					break;
					}
		default: throw new ErrorEnCargarArchivo("Nivel mal cargado");
		}
		return col;
		
	}

	private Premio crearPremio(char c) throws ErrorEnCargarArchivo {
		Premio p=null;
		switch (c){
		case 'N': {p=new Nafta();
					break;
					}
		case 'D': {p=new Balas();
					break;
					}
		case 'U': {p=new Puntos();
					break;
					}
		case 'E': {	break;
					}

		default: throw new ErrorEnCargarArchivo("Nivel mal cargado");
		}
		return p;
		
	}

	private Obstaculo crearObstaculo(char c) throws ErrorEnCargarArchivo {
		Obstaculo o=null;
		switch (c){
		case 'O': {	o=new Concreto();
					break;
					}
		case 'B': {	o=new Caja();
					break;
					}
		case 'P': {	o=new Planta();
					break;
					}
		case 'M': {	o=new Muro();
					break;
					}

		case 'E': {	break;
					}

		default: throw new ErrorEnCargarArchivo("Nivel mal cargado");
		}
		return o;
		
	}

	private Piso crearPiso(char terreno) throws ErrorEnCargarArchivo {
	Piso p= null;
	switch (terreno){
	case 'S': { p= new Arena();
			 	break;
				}
	case 'A': { p= new Asfalto();
				break;
				}
	case 'W': { p= new Agua();
				break;
				}
	case 'F': { p=new Fuego();
				break;
				}
	default: throw new ErrorEnCargarArchivo("Nivel mal Cargado");
	}
	return p;

	}

	/**
	 * Consulta por el piso en una determinada posicion
	 * @param p posicion del terreno buscado
	 * @return Piso en dicha posicion
	 */
	public Piso getTerreno(Posicion p){
		return casillas[p.getX()][p.getY()];
	}
	
	/**
	 * Consulta por el obstaculo en una determinada posicion
	 * @param p posicion del piso a buscar el obstaculo
	 * @return el obstaculo si es que contiene, nulo en caso contrario.
	 */
	public Obstaculo getObstaculo(Posicion p){
		return casillas[p.getX()][p.getY()].getObstaculo();
	}
	
	/**
	 * Consulta por el coleccionable en una determinada posicion
	 * @param p posicion del piso a buscar el obstaculo
	 * @return el coleccionable si es que contiene, nulo en caso contrario.
	 */
	public Coleccionable getColeccionable(Posicion p){
		return casillas[p.getX()][p.getY()].getColeccionable();
	}
	
	/**
	 * Consulta por el premio en una determinada posicion
	 * @param p posicion del piso a buscar el premio
	 * @return el premio si es que contiene, nulo en caso contrario.
	 */
	public Premio getPremio(Posicion p){
		return casillas[p.getX()][p.getY()].getPremio();
	}
	
	/**
	 * Consulta si hay obstaculo en una determinada posicion
	 * @param p posicion en cuestion
	 * @return Verdadero si hay obstaculo, Falso en caso contrario.
	 */
	public boolean hayObstaculo(Posicion p){
		return casillas[p.getX()][p.getY()].hayObstaculo();
	}
	
	/**
	 * Consulta si hay coleccionable en una determinada posicion
	 * @param p posicion en cuestion
	 * @return Verdadero si hay coleccionable, Falso en caso contrario.
	 */
	public boolean hayColeccionable(Posicion p){
		return casillas[p.getX()][p.getY()].hayColeccionable();
	}
	
	/**
	 * Consulta si hay premio en una determinada posicion
	 * @param p posicion en cuestion
	 * @return Verdadero si hay premio, Falso en caso contrario.
	 */
	public boolean hayPremio(Posicion p){
		return casillas[p.getX()][p.getY()].hayPremio();
	}

	/**
	 * Condulta por la posicion inicial del nivel
	 * @return la posicion inicial
	 */
	public Posicion getPosIni(){
		return inicial;
	}
	
	/**
	 * Condulta por la posicion final del nivel
	 * @return la posicion final
	 */
	public Posicion getPosFin(){
		return terminal;
	}
	
	/**
	 * Consulta por la validez de una posicion 
	 * @param p Posicion a consultar
	 * @return Verdadero si la posicion p es valido, falso en caso contrario.
	 */
	public boolean esValida(Posicion p){
		return (p.getX()>=0&&p.getX()<casillas.length)&&(p.getY()>=0&&p.getY()<casillas[0].length);
	}
	
	/**
	 * Consulta por la cantidad de piso a lo ancho
	 * @return la cantidad de pisos en posicion horizontal
	 */
	public int getAncho(){
		return casillas.length;
	}
	
	/**
	 * Consulta por la cantidad de piso a lo largo
	 * @return la cantidad de pisos en posicion vertical
	 */
	public int getAlto(){
		return casillas[0].length;
	}
}
